﻿package com.game.engine.nape
{
    import com.dusk.game.Logger;
    import com.dusk.util.UtilBase;
    import com.game.engine.nape.utils.BodyUserData;
    import com.game.engine.phys.RigidBody;
    import com.game.engine.phys.Vector2D;
    
    import flash.display.DisplayObjectContainer;
    import flash.display.Sprite;
    import flash.utils.Dictionary;
    
    import nape.constraint.PivotJoint;
    import nape.geom.Vec2;
    import nape.phys.Body;
    import nape.phys.BodyList;
    import nape.space.Space;
    import nape.util.ShapeDebug;
    
    public class Nape
    {
        private static var _ins:Nape
        private static var _ignoreCollision:Dictionary = new Dictionary();
        
        private var _gv:Vec2;
        private var _space:Space;
        private var _container:DisplayObjectContainer;
        private var _debug:ShapeDebug;
        
        private var _shapeFactory:NapeShapeFactory;
        private var hand:PivotJoint;
        private var mouseVec2:Vec2;
        
        public static function getIns():Nape
        {
            if(_ins)
            {
                return _ins;
            }
            return null;
        }
        
        public function Nape(container:DisplayObjectContainer, gravX:int = 0, gravY:int = 400)
        {
            Logger.log("init Nape");
            if (!container)
            {
                throw new Error("stage is null");
            }
            _container = container;
            _gv = new Vec2(gravX, gravY);
            _space = new Space(_gv);
            _space.worldAngularDrag = 0;
            _space.worldLinearDrag = 0;
            _ins = this;
            _shapeFactory = new NapeShapeFactory(_space);
            new InteractionListeners(_space);
        }
        
        public static function IgnoreCollision(body1:RigidBody, body2:RigidBody, isIgnore:Boolean = true):void
        {
            var key:String = body1.body.id + "_" + body2.body.id;
            var data:Object = _ignoreCollision[key];
            if (!data)
            {
                data = {};
                _ignoreCollision[key] = data;
            }
            data.a = body1;
            data.b = body2;
            data.ignore = isIgnore;
        }
        
        public static function getIgnoreCollision(body1:RigidBody, body2:RigidBody):Boolean
        {
            var key:String = body1.body.id + "_" + body2.body.id;
            if (_ignoreCollision[key])
            {
                return _ignoreCollision[key].ignore;
            }
            return false;
        }
        
        public static function Clear():void
        {
            if (Nape.getIns())
            {
                if (Nape.getIns().space) Nape.getIns().Clear();
                _ins = null;
                UtilBase.clearAll(_ignoreCollision);
            }
        }
        
        
        public function get hasDebug():Boolean
        {
            return _debug != null;
        }
        
        public function get space():Space
        {
            return _space;
        }
        
        public function get shapeFactory():NapeShapeFactory
        {
            return _shapeFactory;
        }
        
        public function createDebug():void
        {
            if (!_debug)
            {
                _debug = new ShapeDebug(25000, 11500);
                _debug.drawConstraints = true;
            }
            _container.addChild(_debug.display);
        }
        
        public function removeDebug():void
        {
            if (_debug)
            {
                _debug.display.parent.removeChild(_debug.display);
            }
            _debug = null;
        }
        
        public function render(time:Number):void
        {
            if (!_space)
            {
                return;
            }
            _space.step(time);
        }
        
        public function renderAnimate():void
        {
            if (!_space)
            {
                return;
            }
            if (_debug)
            {
                _debug.clear();
            }
            if (_debug)
            {
                _debug.draw(_space);
                _debug.flush();
                if(_container.contains(_debug.display))
                {
                    _container.setChildIndex(_debug.display, _container.numChildren - 1);
                }
            }
            if (hand != null)
            {
                if (hand.active)
                {
                    hand.anchor1.setxy(_container.mouseX, _container.mouseY);
                }
            }
        }
        
        public function getBodyAtMouse():Body
        {
            var bodyPressed:Body;
            mouseVec2 = new Vec2(_container.mouseX, _container.mouseY);
            var bodiesUnderMouse:BodyList = space.bodiesUnderPoint(mouseVec2);
            bodiesUnderMouse.foreach(function (bo:Body):void
            {
                bodyPressed = bo;
            });
            return bodyPressed;
        }
        
        public function stopDragBody():void
        {
            if (hand != null)
            {
                hand.active = false;
            }
        }
        
        public function startDragBody(body:Body):void
        {
            if (body == null || !body.isDynamic())
            {
                return;
            }
            if (hand == null)
            {
                hand = new PivotJoint(space.world, null, new Vec2(), new Vec2());
                hand.space = space;
                hand.stiff = false;
            }
            hand.active = true;
            hand.body2 = body;
            hand.anchor1.set(mouseVec2);
            hand.anchor2 = body.worldPointToLocal(mouseVec2);
        }
        
        public function Clear():void
        {
            while (space.bodies.length > 0)
            {
                var bo:Body = space.bodies.at(0);
                space.bodies.remove(bo);
            }
            _shapeFactory = null;
            _container = null;
        }
    }
}